package cn.deschen.eshop.auth.filter;

import cn.deschen.eshop.auth.service.DynamicSecurityService;
import cn.hutool.core.util.URLUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import sun.security.krb5.Config;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * @Author hanbin_chen
 * @Description 动态权限数据源，用于获取接口的对应的权限
 * @DateTime 2021/1/21 15:35
 * @Version V1.0.0
 */
@Slf4j
@Component
public class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    @Autowired
    private DynamicSecurityService dynamicSecurityService;

    private static Map<String, ConfigAttribute> configAttributeMap = null;

    /**
     * 初始化资源权限映射
     */
    @PostConstruct
    public void loadDataSource() {
        configAttributeMap = dynamicSecurityService.loadDataSource();
    }

    /**
     * 返回本次访问需要的权限，可以有多个权限
     * @param object FilterInvocation对象，可以得到request等web资源。
     * @return
     * @throws IllegalArgumentException
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        // 判断资源权限的映射是否存在
        if (null == configAttributeMap) {
            this.loadDataSource();
        }
        // 保存请求路径对应的权限资源
        List<ConfigAttribute> configAttributes = new ArrayList<>();
        // 获取当前的请求路径
        String url = ((FilterInvocation) object).getRequestUrl();
        String path = URLUtil.getPath(url);
        PathMatcher pathMatcher = new AntPathMatcher();
        // 判断请求路径对应的权限
        configAttributeMap.forEach((patternUrl, attribute) -> {
            if (pathMatcher.match(patternUrl, path)) {
                configAttributes.add(attribute);
            }
        });
        // 未设置操作请求权限，返回空集合
        return configAttributes;
    }

    /**
     * 如果返回了所有定义的权限资源，Spring Security会在启动时校验每个ConfigAttribute是否配置正确，不需要校验直接返回null。
     * @return
     */
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    /**
     * 返回类对象是否支持校验，web项目一般使用FilterInvocation来判断，或者直接返回true
     * @param clazz
     * @return
     */
    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}
